/**    
 * 文件名：SendHttpMsgHandler.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年6月27日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.common.util;

import java.io.File;
import java.net.URL;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import com.google.gson.JsonObject;
import com.logic.landseaserver.common.LandeaConstants;
import com.logic.landseaserver.common.LandseaErrorMessageEnum;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.CommonResultCode;
import com.logic.landseaserver.domain.SendMsgObject;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：SendHttpMsgHandler</br>
 * 类描述：发送HTTP消息帮助类</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年6月27日 下午1:44:17</br>
 * 
 * @version 1.0
 *
 */
public abstract class SendHttpMsgHandler
{
    private static final Logger LOGGER = LoggerFactory.getLogger(SendHttpMsgHandler.class);
    
    /**
     * 
     * [简要描述]：获取默认的httpHeader</br>
     * [详细描述]：application/json;charset=UTF-8</br>
     * [作者]：Aaron(2017-06-27)</br>
     *
     * @return HttpHeaders
     *
     */
    private static HttpHeaders getDefaultHttpHeader()
    {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        return headers;
    }
    
    /**
     * 
     * [简要描述]：以json格式发送post请求</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-06-27)</br>
     *
     * @param SendMsgObject 消息对象
     * @throws LandseaException 有可能发生的异常
     *
     */
    public static void sendPostJsonMessage(SendMsgObject sendMsgObject)
        throws LandseaException
    {
        try
        {
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = getDefaultHttpHeader();
            
            if (StringUtils.isEmpty(sendMsgObject.getAccept()))
            {
                headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            }
            else
            {
                headers.add("Accept", sendMsgObject.getAccept());
            }
            if (StringUtils.isEmpty(sendMsgObject.getContentType()))
            {
                headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            }
            else
            {
                headers.setContentType(MediaType.valueOf(sendMsgObject.getContentType()));
            }
            
            JsonObject paramJson = JsonObjectUtils.map2JsonObject(sendMsgObject.getBodyParamMap());
            HttpEntity<String> postEntity = new HttpEntity<String>(paramJson.toString(), headers);
            
            // 记录发送日志
            LOGGER.info("sendPostJsonMsg|Request|" + postEntity.toString());
            
            String result = restTemplate.postForObject(sendMsgObject.getUrl(), postEntity, String.class);
            
            LOGGER.info("sendPostJsonMsg|Response|" + result);
            
            // 结果为json字符串，需要将字符串转换成Map以便处理
            Map<String, Object> resultMap = JsonObjectUtils.jsonStr2map(result);
            sendMsgObject.setResponseMap(resultMap);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("sendPostJsonMsg|Failed|" + sendMsgObject.toString());
            throw LandseaException.createException(LandseaErrorMessageEnum.COMMON_SEND_MSG_ERROR, e);
        }
    }
    
    /**
     * 
     * [简要描述]：发送https的post消息</br>
     * [详细描述]：证书为File对象</br>
     * [作者]：Aaron(2017-07-22)</br>
     *
     * @param url URL地址
     * @param content 发送的内容
     * @param certificate 证书File
     * @param keyPassword 证书密码
     * @return 结果的字符串
     * @throws Exception
     *
     */
    public static String sendHttpsPost(String url, String content, File certificate, String keyPassword)
        throws LandseaException
    {
        try
        {
            if (StringUtils.isEmpty(url))
            {
                return null;
            }
            
            SSLContextBuilder sSLContextBuilder =
                SSLContexts.custom().loadTrustMaterial(certificate, keyPassword.toCharArray());
            
            return sendHttpsPost(url, content, sSLContextBuilder, keyPassword);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("sendHttpsPost|send or recive https message failed. content=" + content, e);
            throw LandseaException.createException(CommonResultCode.E00050001, e);
        }
    }
    
    /**
     * 
     * [简要描述]：发送https的post消息</br>
     * [详细描述]：证书为URL</br>
     * [作者]：Aaron(2017-07-22)</br>
     *
     * @param url URL地址
     * @param content 发送的内容
     * @param certificateUrl 证书URL对象
     * @param keyPassword 证书密码
     * @return 结果的字符串
     * @throws Exception
     *
     */
    public static String sendHttpsPost(String url, String content, URL certificateUrl, String keyPassword)
        throws LandseaException
    {
        try
        {
            if (StringUtils.isEmpty(url))
            {
                return null;
            }
            
            SSLContextBuilder sSLContextBuilder =
                SSLContexts.custom().loadTrustMaterial(certificateUrl, keyPassword.toCharArray());
            
            return sendHttpsPost(url, content, sSLContextBuilder, keyPassword);
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("sendHttpsPost|send or recive https message failed. content=" + content, e);
            throw LandseaException.createException(CommonResultCode.E00050001, e);
        }
    }
    
    private static String sendHttpsPost(String url, String content, SSLContextBuilder sSLContextBuilder,
        String keyPassword)
        throws LandseaException
    {
        if (StringUtils.isEmpty(url))
        {
            return null;
        }
        
        CloseableHttpClient httpclient = null;
        CloseableHttpResponse response = null;
        try
        {
            SSLContext sSLContext = sSLContextBuilder.build();
            
            SSLConnectionSocketFactory sSLConnectionSocketFactory = new SSLConnectionSocketFactory(sSLContext);
            
            // 超时时间
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)
                .setConnectTimeout(30000)
                .setConnectionRequestTimeout(5000)
                .build();
            
            // 获取httpClient
            httpclient = HttpClients.custom()
                .setSSLSocketFactory(sSLConnectionSocketFactory)
                .setDefaultRequestConfig(defaultRequestConfig)
                .build();
            
            HttpPost httpPost = new HttpPost(url);
            
            // 设定直接post的数据内容
            if (StringUtils.isNotEmpty(content))
            {
                org.apache.http.HttpEntity entity = new StringEntity(content, LandeaConstants.UTF8_CHARSET);
                httpPost.setEntity(entity);
            }
            
            // 发送
            response = httpclient.execute(httpPost);
            org.apache.http.HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null)
            {// 获取返回结果
                String respContent = EntityUtils.toString(httpEntity, LandeaConstants.UTF8_CHARSET);
                return respContent;
            }
            
            return null;
        }
        catch (Exception e)
        {
            LOGGER.error("sendHttpsPost|send or recive https message failed. content=" + content, e);
            throw LandseaException.createException(CommonResultCode.E00050001, e);
        }
        finally
        {
            try
            {
                if (null != httpclient)
                {
                    httpclient.close();
                }
                if (null != response)
                {
                    response.close();
                }
            }
            catch (Exception e2)
            {
                LOGGER.error(
                    "sendHttpsPost|send or recive https message failed, close connection failed. content=" + content,
                    e2);
                throw LandseaException.createException(CommonResultCode.E00050001, e2);
            }
        }
    }
    
    /**
     * 
     * [简要描述]：将参数拼接在url后面</br>
     * [详细描述]：url?a=a&b=b...</br>
     * [作者]：Aaron(2017-07-27)</br>
     *
     * @param url 原始Url
     * @param paramMap 参数列表
     * @return 拼装好的url
     *
     */
    public static String assembleParam(String url, Map<String, Object> paramMap)
    {
        if (StringUtils.isEmpty(url) || MapUtils.isEmpty(paramMap))
        {
            return url;
        }
        
        url = url + "?" + getUrlParamsByMap(paramMap);
        
        return url;
    }
    
    /**
     * 
     * [简要描述]：将Map转换成url参数列表</br>
     * [详细描述]：a=a&b=b.....</br>
     * [作者]：Aaron(2017-07-27)</br>
     *
     * @param map
     * @return
     *
     */
    public static String getUrlParamsByMap(Map<String, Object> map)
    {
        if (MapUtils.isEmpty(map))
        {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : map.entrySet())
        {
            sb.append(entry.getKey() + "=" + entry.getValue());
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&"))
        {
            s = StringUtils.substringBeforeLast(s, "&");
        }
        return s;
    }
}
